using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models;

namespace SumerCoreDevOps.Infrastructure.Tcp;

/// <summary>
/// 主节点端点配置
/// </summary>
public class MasterEndpoint
{
    public string Host { get; set; } = string.Empty;
    public int Port { get; set; }
    public int Priority { get; set; } = 1;
}

/// <summary>
/// TCP 多主节点客户端（执行节点端，支持连接多个主节点）
/// </summary>
public class TcpMultiMasterClient : IDisposable
{
    private readonly ILogger<TcpMultiMasterClient> _logger;
    private readonly TcpMessageCodec _codec;
    private readonly List<MasterEndpoint> _masterEndpoints;
    private readonly ConcurrentDictionary<string, MasterConnection> _connections = new();
    private readonly string _connectionStrategy;
    private bool _disposed;

    public event Func<string, TcpMessageType, object, Task>? OnMessageReceived;
    public event Func<string, Task>? OnConnected;
    public event Func<string, Task>? OnDisconnected;

    public TcpMultiMasterClient(
        ILogger<TcpMultiMasterClient> logger,
        byte[] aesKey,
        List<MasterEndpoint> masterEndpoints,
        string connectionStrategy = "ConnectAll")
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _codec = new TcpMessageCodec(aesKey);
        _masterEndpoints = masterEndpoints ?? throw new ArgumentNullException(nameof(masterEndpoints));
        _connectionStrategy = connectionStrategy;

        if (_masterEndpoints.Count == 0)
        {
            throw new ArgumentException("At least one master endpoint must be provided", nameof(masterEndpoints));
        }

        _logger.LogInformation("TcpMultiMasterClient initialized with {Count} masters, strategy: {Strategy}",
            _masterEndpoints.Count, _connectionStrategy);
    }

    /// <summary>
    /// 连接到所有主节点
    /// </summary>
    public async Task ConnectAsync(CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("Connecting to masters with strategy: {Strategy}", _connectionStrategy);

        if (_connectionStrategy == "ConnectAll")
        {
            await ConnectToAllMastersAsync(cancellationToken);
        }
        else if (_connectionStrategy == "PrimaryWithFailover")
        {
            await ConnectToPrimaryMasterAsync(cancellationToken);
        }
        else
        {
            throw new ArgumentException($"Unknown connection strategy: {_connectionStrategy}");
        }
    }

    /// <summary>
    /// 连接到所有主节点
    /// </summary>
    private async Task ConnectToAllMastersAsync(CancellationToken cancellationToken)
    {
        var tasks = _masterEndpoints.Select(endpoint => ConnectToMasterAsync(endpoint, cancellationToken));
        var results = await Task.WhenAll(tasks);

        var successCount = results.Count(r => r);
        _logger.LogInformation("Connected to {SuccessCount}/{TotalCount} masters",
            successCount, _masterEndpoints.Count);

        if (successCount == 0)
        {
            throw new InvalidOperationException("Failed to connect to any master");
        }
    }

    /// <summary>
    /// 连接到主主节点（优先级最高的）
    /// </summary>
    private async Task ConnectToPrimaryMasterAsync(CancellationToken cancellationToken)
    {
        var orderedEndpoints = _masterEndpoints.OrderBy(e => e.Priority).ToList();

        foreach (var endpoint in orderedEndpoints)
        {
            if (await ConnectToMasterAsync(endpoint, cancellationToken))
            {
                _logger.LogInformation("Connected to primary master: {Host}:{Port}",
                    endpoint.Host, endpoint.Port);
                return;
            }
        }

        throw new InvalidOperationException("Failed to connect to any master");
    }

    /// <summary>
    /// 连接到指定主节点
    /// </summary>
    private async Task<bool> ConnectToMasterAsync(MasterEndpoint endpoint, CancellationToken cancellationToken)
    {
        var masterId = $"{endpoint.Host}:{endpoint.Port}";

        try
        {
            _logger.LogInformation("Connecting to master: {MasterId}...", masterId);

            var client = new System.Net.Sockets.TcpClient();
            await client.ConnectAsync(endpoint.Host, endpoint.Port);

            var connection = new MasterConnection
            {
                MasterId = masterId,
                Endpoint = endpoint,
                Client = client,
                Stream = client.GetStream(),
                IsConnected = true,
                LastHeartbeat = DateTime.UtcNow
            };

            _connections.TryAdd(masterId, connection);

            // 启动接收循环
            _ = Task.Run(async () => await ReceiveLoopAsync(connection, cancellationToken), cancellationToken);

            _logger.LogInformation("Connected to master: {MasterId}", masterId);

            if (OnConnected != null)
            {
                await OnConnected(masterId);
            }

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to connect to master: {MasterId}", masterId);
            return false;
        }
    }

    /// <summary>
    /// 发送消息到所有连接的主节点
    /// </summary>
    public async Task SendToAllAsync<T>(TcpMessageType messageType, T body, bool compress = false)
        where T : class
    {
        var tasks = _connections.Values
            .Where(c => c.IsConnected)
            .Select(c => SendToMasterAsync(c.MasterId, messageType, body, compress));

        await Task.WhenAll(tasks);
    }

    /// <summary>
    /// 发送消息到指定主节点
    /// </summary>
    public async Task SendToMasterAsync<T>(string masterId, TcpMessageType messageType, T body, bool compress = false)
        where T : class
    {
        if (!_connections.TryGetValue(masterId, out var connection) || !connection.IsConnected)
        {
            throw new InvalidOperationException($"Not connected to master: {masterId}");
        }

        try
        {
            byte[] data = _codec.Encode(messageType, body, compress);
            await connection.Stream.WriteAsync(data);
            await connection.Stream.FlushAsync();

            _logger.LogDebug("Sent message {MessageType} to master {MasterId}, size: {Size} bytes",
                messageType, masterId, data.Length);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send message to master: {MasterId}", masterId);
            await DisconnectMasterAsync(masterId);
            throw;
        }
    }

    /// <summary>
    /// 接收消息循环
    /// </summary>
    private async Task ReceiveLoopAsync(MasterConnection connection, CancellationToken cancellationToken)
    {
        try
        {
            while (connection.IsConnected && !cancellationToken.IsCancellationRequested)
            {
                try
                {
                    var (messageType, body) = await _codec.ReadFromStreamAsync(connection.Stream, cancellationToken);

                    if (OnMessageReceived != null)
                    {
                        await OnMessageReceived(connection.MasterId, messageType, body);
                    }
                }
                catch (EndOfStreamException)
                {
                    _logger.LogWarning("Connection closed by master: {MasterId}", connection.MasterId);
                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error receiving message from master: {MasterId}", connection.MasterId);
                    break;
                }
            }
        }
        finally
        {
            await DisconnectMasterAsync(connection.MasterId);
        }
    }

    /// <summary>
    /// 断开所有主节点连接
    /// </summary>
    public async Task DisconnectAllAsync()
    {
        _logger.LogInformation("正在断开所有主节点连接...");

        var masterIds = _connections.Keys.ToList();
        foreach (var masterId in masterIds)
        {
            await DisconnectMasterAsync(masterId);
        }

        _logger.LogInformation("已断开所有主节点连接");
    }

    /// <summary>
    /// 重新连接到主节点
    /// </summary>
    public async Task ReconnectAsync(List<MasterEndpoint> newEndpoints, CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("正在重新连接到主节点...");

        // 断开所有现有连接
        await DisconnectAllAsync();

        // 更新主节点列表
        _masterEndpoints.Clear();
        _masterEndpoints.AddRange(newEndpoints);

        // 重新连接
        await ConnectAsync(cancellationToken);

        _logger.LogInformation("重新连接完成");
    }

    /// <summary>
    /// 断开与主节点的连接
    /// </summary>
    private async Task DisconnectMasterAsync(string masterId)
    {
        if (!_connections.TryRemove(masterId, out var connection))
        {
            return;
        }

        connection.IsConnected = false;

        try
        {
            connection.Stream?.Dispose();
            connection.Client?.Dispose();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error closing connection to master: {MasterId}", masterId);
        }

        _logger.LogInformation("Disconnected from master: {MasterId}", masterId);

        if (OnDisconnected != null)
        {
            await OnDisconnected(masterId);
        }

        // 如果是 PrimaryWithFailover 模式且断开的是唯一连接，尝试重连
        if (_connectionStrategy == "PrimaryWithFailover" && _connections.Count == 0)
        {
            _logger.LogWarning("Lost connection to primary master, attempting failover...");
            _ = Task.Run(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(5));
                try
                {
                    await ConnectToPrimaryMasterAsync(CancellationToken.None);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Failover connection failed");
                }
            });
        }
    }

    /// <summary>
    /// 获取所有连接的主节点
    /// </summary>
    public List<string> GetConnectedMasters()
    {
        return _connections.Values
            .Where(c => c.IsConnected)
            .Select(c => c.MasterId)
            .ToList();
    }

    /// <summary>
    /// 检查是否连接到任何主节点
    /// </summary>
    public bool IsConnected()
    {
        return _connections.Values.Any(c => c.IsConnected);
    }

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        foreach (var connection in _connections.Values)
        {
            connection.IsConnected = false;
            connection.Stream?.Dispose();
            connection.Client?.Dispose();
        }

        _connections.Clear();
        _disposed = true;
    }
}

/// <summary>
/// 主节点连接信息
/// </summary>
internal class MasterConnection
{
    public string MasterId { get; set; } = string.Empty;
    public MasterEndpoint Endpoint { get; set; } = null!;
    public System.Net.Sockets.TcpClient Client { get; set; } = null!;
    public NetworkStream Stream { get; set; } = null!;
    public bool IsConnected { get; set; }
    public DateTime LastHeartbeat { get; set; }
}
